var log4js = require('log4js');
var logger = log4js.getLogger('DaifugoPlayer');
var player = require('../../../common/game/Player');
var util = require("util");
var DfgAI = require('./../AICore/DfgAI');
var GameRule = require('./../AICore/DfgRule');
var aiutils = require('./../AICore/aiutils');

var PlayerStatus = {
    Normal: 0,
    Daifugo: 1,
    Fugo: 2,
    Hinmin: 3,
    Daihinmin: 4
};

// The betting money
var BettingMoney = 100; // TODO: Hardcode, get it from client

// The prize for each rank
var PrizeRank = [0, 3, 1.5, 1, 0];

// Number of Joker card
Card_Joker = aiutils.Card_Joker;

/*
*       @function
*   Init a Daifugo Player
* */
function DaifugoPlayer(name, config) {
    //var deviceLog = (deviceName == undefined)?('CPU' + name):deviceName;
   this.mylog = log4js.getLogger('[Player-' + ']');
    this.mylog.trace("enter constructor");
    player.Player.call(this, name, config);
    /**
     *      @enum
     *      Player Status
     */
    this.mCards = [];
    this.mDCards = [];
    this.status = PlayerStatus.Normal;
    this.dSolution = [];
    this.mIndex = 0;
    this.lenCards = 0;
    this.mCardsTable = [];
    this.otherLenCard = [];
    this.on('data', DaifugoPlayer.processDataAMQ);
    this.on('client_data', DaifugoPlayer.processClientData);

}

// Inherit the prototype methods from Table object into DaifugoPlayer
util.inherits(DaifugoPlayer, player.Player);

module.exports = DaifugoPlayer;

DaifugoPlayer.DaifugoPlayer = DaifugoPlayer;
DaifugoPlayer.Player = DaifugoPlayer;

/*
*
*       @function: Process data receiving from the client
*
* */
DaifugoPlayer.processClientData = function (data, that) {
    this.mylog.trace('enter processClientData');

    switch (data.action) {
        case MessageTable.DEAL_CARD:
            that.dealCards(data);
            break;
        default:
            break;
    }
};

/*
*   @function: process data receiving from the DaifugoTable
*
* */
DaifugoPlayer.processDataAMQ = function (data, that) {
    var me = that;
    switch (data.action) {
        case 'start':
            // Send message to init the game
            this.mylog.info('Send start to begin init table');

            // Init the player data


            // Check the money on the platform
            if (that.type === "user"){
                var levelCPU = {dataLevelCPU: [0,1,2]};
                that.sendLevelCPU(levelCPU);
            }
            else {
            }
            break;

        case MessageTable.LEVEL_CPU:
            // Get the AI level
            that.mylog.info("Get level CPU from server successfully");
            that.chTable.sendMessage({
                action: MessageTable.GET_CARD,
                player: that.name
            })
            if (that.type == "ai") {
                that.setLevel(data.levelCPU[that.name - 2]);
            }
            break;

        case MessageTable.GET_CARD:
            that.initCardTable();
            if (that.name == data.player) {
                that.mCards = data.cardData[4 - that.name].myCards;
                that.setdSolution(GameRule.getAllDealingCards(that.mCards));
                for(var i = 0; i< data.cardData.length; i++){
                    that.otherLenCard[i] = data.cardData[i].myCards.length;
                }
                if (that.type == "user") {
                    // cData = Card Data
                    var cData = {}
                    cData.action = MessageTable.GET_CARD;
                    cData.cardData = data.cardData[4 - that.name];
                    var rData = {};
                    rData.success = true;
                    rData.body = cData
                    that.socket.emit('message', rData);
                    that.startCardGame();
                }
            }
            break;

        case MessageTable.GET_SOLUTION:
            // Get the solution
            if (data.player == that.name) {
                if (that.type == "user") {
                    var body = {};
                    body.action = MessageTable.GET_SOLUTION;
                    body.solution = that.cutSolution(data.tour, data.cardsLock, data.mDCards);
                    var solutionData = {};
                    solutionData.success = true;
                    solutionData.body = body;
                    that.socket.emit('message', solutionData);
                }
                else {
                    var cpuSolution = {};
                    cpuSolution.dealCard = that.findSolution(data.tour, data.cardsLock);
                    setTimeout(function () {
                        that.dealCards(cpuSolution);
                    }, data.timeToThink * 1000);
                }
            }
            break;

        case MessageTable.DEAL_PROCESS:
            var joker = null;
            var that = this;

            if ((4 - data.player) == that.name) {
                // Update the card table
                for (var i = 0; i < data.removecard.length; i++) {
                    var card = data.removecard[i];
                        that.mCardsTable[card.mRank][card.mColor] = false;
                }
            }
            break;

        case MessageTable.GAME_STATUS:
            var that = this;
            // Update the card table
            for (var i = 0; i < data.data.length; i++) {
                var card = data.data[i];
                    that.mCardsTable[card.mRank][card.mColor] = false;
            }
            this.otherLenCard[data.iplayer] -=(data.data.length);
            // When finish tour
            if (data.status.isTourFinish == true) {
                that.mDCards = [];
            }
            else{
                that.mDCards.push(data.data);
            }

            // send the status to user
            if (that.type == "user") {
                var sttData = {};
                sttData.success = true;
                sttData.body = data;
                that.socket.emit('message', sttData);
            }
            break;

        case MessageTable.GET_RESULT:
            if (that.type == "user") {
                var resultData = {};
                resultData.success = true;
                resultData.body = data;
                that.socket.emit('message', resultData);
                // Platform with rank
                var myrank = resultData.body.result[4 - that.name].rank;
                var myprize = BettingMoney*PrizeRank[myrank];

                that.clearGameData();
            }
            break;
        default:
            break;
    }
};

/*
*
*       @function: send the dealing card to the table
*
*       TODO: Remove the trace
*
* */
DaifugoPlayer.prototype.dealCards = function (data) {
    this.removeSolution(data.dealCard);
    if (this.chTable !== null) {
        var rData = {
            action: MessageTable.DEAL_CARD,
            dealcard: data.dealCard,
            type: this.type,
            player: this.name
        };
        this.chTable.sendMessage(rData);
    } else {
        this.mylog.warn('transmit channel is null');
    }
};
/*
 *   @function: Send the card's information
 *   + Level CPU
 * */
DaifugoPlayer.prototype.sendLevelCPU = function (clientData) {
    if (this.chTable !== null) {
        var data = {
            action: MessageTable.LEVEL_CPU,
            levelCPU: clientData.dataLevelCPU
        };
        this.mylog.info('send level CPU to table');
        this.mylog.info(data);
        this.chTable.sendMessage(data);
    }
    else {
        this.mylog.error('table channel is null, cannot connect to queue server');
    }
};
/*
*
*       @function:Send Request message start game to Table
*
* */
DaifugoPlayer.prototype.startCardGame = function () {
    var that = this;
    setTimeout(that.chTable.sendMessage({
        action: MessageTable.START_CARD_GAME,
        player: that.name,
        type: that.type
    }), 3000)
    ;
};
/*
*
*  @function: set Level for Player
*
* */
DaifugoPlayer.prototype.setLevel = function (level) {
    this.mLevel = level;
};
/*
*
*  @function: Get and Set solution for Player
*
* */
DaifugoPlayer.prototype.setdSolution = function (solutions) {
    var first_dSolution = [];
    var second_dSolution = [];
    first_dSolution = solutions;
    for(var i = 0; i < first_dSolution.length; i++){
        if(first_dSolution[i].length == 2 && first_dSolution[i][0].mRank != 15 && (first_dSolution[i][1].mColor + first_dSolution[i][0].mColor != 1) && (first_dSolution[i][1].mColor + first_dSolution[i][0].mColor != 5) ){

        }
        else{
            second_dSolution.push(first_dSolution[i]);
        }
    }
    this.dSolution = second_dSolution;
    this.cdSolution = second_dSolution.slice(0, second_dSolution.length);

};
/*
*
*  @function: Add array card for Player
*
* */
DaifugoPlayer.prototype.addCard = function (card) {
    card.deal = false;
    this.mCards.push(card);
    this.lenCards++;
};
/*
*
*  @function: Remove card and solution of PLayer
*
* */
DaifugoPlayer.prototype.removeSolution = function (cards) {
    var nsame = 0;
    this.mylog.info("Dealed cards");
    this.mylog.info(cards);
    var solutionclons = this.dSolution.slice(0, this.dSolution.length);
    var newdsolution = [];     // TODO: Revert the previous version for the performance
    for (var i = 0; i < this.dSolution.length; i++) {
        var find = false;
        for (var k = 0; k < this.dSolution[i].length && !find; k++) {
            for (var j = 0; j < cards.length; j++) {
                if (cards[j].index == this.dSolution[i][k].index) {
                    this.mCards[cards[j].index].deal = true;
                    find = true;
                    break;
                }
            }
        }
        if (find) {
            nsame++;
            this.mylog.info("Removed cards");
            this.mylog.info(this.dSolution[i]);
        }
        else {
            newdsolution.push(this.dSolution[i]);
        }
    }

    //this.dSolution = this.dSolution.slice(0, this.dSolution.length - nsame);
    this.dSolution = newdsolution;
    this.lenCards -= cards.length; // TODO: check this member is not set to 0 when all cards are removed
};
DaifugoPlayer.prototype.cutSolution = function (tour, cardlock) {
    var that = this;
    var Tour = tour;
    var threshold = 0; // The threshold to compare two solution
    var cardsLock = cardlock; // The current cards on the tour
    if (that.mDCards.length > 0) {
        var ret = [];
        if(cardsLock.length == 0){
            this.mylog.info("Use dSolution");
            this.mylog.info(this.dSolution);
            for (var i = 0; i < this.dSolution.length; i++) {
                if (aiutils.checkPatternFail(this.dSolution[i], this.mCards) == true) {
                    ret.push(this.dSolution[i]);
                }
            }
            this.mDCards.push(cardlock);
            return ret;
        }
        this.mylog.info("Not Use dSolution");
        for (var i = 0; i < this.dSolution.length; i++) {
            var d = aiutils.cardsCompare(cardsLock, this.dSolution[i]);

                if (d < threshold && aiutils.checkPatternFail(this.dSolution[i], this.mCards) == true) {

                    this.mylog.info("Use this solution: ");
                    this.mylog.info(this.dSolution[i]);
                    ret.push(this.dSolution[i]);

                }

        }
        this.mDCards.push(cardlock);
        return ret;

    }
    else {
        this.mylog.info("Use dSolution");
        this.mylog.info(this.dSolution);
        var ret = [];
        for (var i = 0; i < this.dSolution.length; i++) {
            if (aiutils.checkPatternFail(this.dSolution[i], this.mCards) == true) {
                ret.push(this.dSolution[i]);
            }
        }
        this.mDCards.push(cardlock);
        return ret;
    }

};
/*
 * // Init the cards Table
 *
 * */
DaifugoPlayer.prototype.initCardTable = function () {
    var that = this;
    for (var i = 3; i < Card_Joker; i++) {
        this.mCardsTable[i] = [];
        for (var j = 0; j < 4; j++) {
            that.mCardsTable[i][j] = true;
        }
    }
};

/*
*       @function
*       Find solution for AI player
* */
DaifugoPlayer.prototype.findSolution = function (tour, cardsLock) {
    var that = this;
    var mySolutions = this.cutSolution(tour, cardsLock);
    var Tour = tour;
    var isLockingHand = tour.isLockingHand;
    var oPlayers = this.otherLenCard;
    var index = 4 - that.name;
    var tPlayer = 0;
    //for (var i = 1; i < game.mPlayers.length + 1; i++) {
    //    oPlayers[i - 1] = game.mPlayers[(this.mIndex + i) % game.mPlayers.length].lenCards;
    //}
    return DfgAI.findSolution(mySolutions,isLockingHand, that.mLevel, that.mCards, this.mCardsTable, oPlayers, this.dSolution,cardsLock);
};

/*
*       @function
*       Throw an error
* */
DaifugoPlayer.prototype.throwError = function (err) {
    var rData = {
        success: true,
        body: {
            action: MessageTable.ERROR,
            error: err
        }
    };
    this.socket.emit('message', rData);
};

/*
*       @function
*       Clear all game data
* */
DaifugoPlayer.prototype.clearGameData = function(){
    var that = this;
    that.chTable.sendMessage({
        action: MessageTable.END_GAME
    });
    this.mCards = [];
    this.mDCards = [];
    this.status = PlayerStatus.Normal;
    this.dSolution = [];
    this.mIndex = 0;
    this.lenCards = 0;
    this.mCardsTable = [];
};

var MessageTable = {
    DO_SMTH: "DO_SMTH",
    RE_SMTH: "RE_SMTH",
    DEAL_CARD: "DEAL_CARD",
    PASS_CARD: "PASS_CARD",
    FIND_ROOM: "find_table",
    ROOM_TALK: "ROOM_TALK",
    GET_NAME: "GET_NAME",
    GET_CARD: "GET_CARD",
    EXCHANGE_CARD: "EXCHANGE_CARD",
    GET_SOLUTION: "GET_SOLUTION",
    GET_RESULT: "GET_RESULT",
    SER_INFO: "USER_INFO",
    GAME_STATUS: "GAME_STATUS",
    LEVEL_CPU: "LEVEL_CPU",
    START_CARD_GAME: "START_CARD_GAME",
    DEAL_PROCESS: "DEAL_PROCESS",
    END_GAME: "END_GAME",
    ERROR: "ERROR"
};
